#ifdef __GNUG__
#pragma implementation
#endif

#include "UnixPtty.h"
#include "Class.h"
#include "File.h"
#include "SysEvtHandler.h"
#include "UnixSystem.h"
#include "ET_stdio.h"

extern "C" {
	//---- C++ interface to unixptty.c
	int unixptty_SpawnSlave(const char *name, const char **args,
		PttyChars*, int *slavepid, int *masterfd, char *slavepty);
		// open a pseudotty, fork a process name with args and connect 0,1,2 to
		// slave side, pid returns the pid of the process on the slave side
		// pid is the process group of the process on the slave side
		// name is the name of ptty

	int unixptty_KillChild(int slavepid, const char *slavepty);
	int unixptty_BecomeConsole(int fd);
	int unixptty_Flush(int fd);
	int unixptty_GetMode(int fd);
	int unixptty_SetWinSize(int fd, int rows, int cols);
}

//---- PttyInputHandler --------------------------------------------------------

class PttyInputHandler : public FileHandler {
	PttyConnection *pttyHandler;
public:
	PttyInputHandler(PttyConnection *pth, int fd) : FileHandler(fd, 1)
		{ pttyHandler= pth; }
	bool ReadNotify()
		{ pttyHandler->InputNotify(); return TRUE; }
};

//---- UnixPtty ----------------------------------------------------------------

NewMetaImpl(UnixPtty,PttyImpl, (TS(slavepty), TP(inputHandler)));

UnixPtty::UnixPtty()      
{
}

UnixPtty::~UnixPtty()
{
	KillChild();
	SafeDelete(slavepty);
	SafeRemove(inputHandler);
}

int UnixPtty::SpawnSlave(const char *name, const char **args)
{
	char slavename[1000];
	int rc= unixptty_SpawnSlave(name, args, &pttychars, &slavepid,
			&masterfd, slavename);
	slavepty= strsave(slavename);
	File::AddFdName(masterfd, slavepty, "UnixPtty::SpawnSlave");
	if (rc >= 0) {
		inputHandler= new PttyInputHandler(pty, masterfd);
		gSystem->AddFileHandler(inputHandler);
	}
	return rc;
}

int UnixPtty::KillChild()
{
	int rc;
	if (masterfd >= 0) {
		File::Close(masterfd, "UnixPtty::KillChild");
		rc= ::unixptty_KillChild(slavepid, slavepty);
		masterfd= -1;
	}
	return rc;
}

int UnixPtty::Flush()
{
	if (masterfd >= 0)
		return ::unixptty_Flush(masterfd);
	return -1;
}

int UnixPtty::GetMode()
{
	if (masterfd >= 0)
		return ::unixptty_GetMode(masterfd);
	return -1;
}

int UnixPtty::BecomeConsole()
{
	int rc= -1, fd;
	if (slavepty) {
		if ((fd= File::Open(slavepty, 2)) >= 0) {
			rc= ::unixptty_BecomeConsole(fd);
			File::Close(fd);
		} else
			ErrorNotify(-1, form("Cannot become console %s\n", slavepty));
	}
	return rc;
}

int UnixPtty::SetWinSize(const Point &cr)
{
	int rc= -1, fd;
	if (slavepty) {
		if ((fd= File::Open(slavepty, 2)) > 0) {
			rc= ::unixptty_SetWinSize(fd, cr.y, cr.x);
			File::Close(fd);
		} else
			ErrorNotify(-1, form("Cannot open slave %s\n", slavepty));
	}
	return rc;              
}

